package com.example.controllers;

import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import java.nio.charset.Charset;
import java.util.Arrays;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;

import com.example.ShoppingCartApiApplication;
import com.example.models.Customer;
import com.example.repositories.CustomerRepository;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ShoppingCartApiApplication.class)
@WebAppConfiguration
@IntegrationTest({"server.port=9090"})
public class CustomerControllerIT {
	
	private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(),
            Charset.forName("utf8"));

    private MockMvc mockMvc;
    
    private HttpMessageConverter mappingJackson2HttpMessageConverter;

    private Customer customer1, customer2;
    
    @Autowired
    private CustomerRepository customerRepository;
    
    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    void setConverters(HttpMessageConverter<?>[] converters) {

        this.mappingJackson2HttpMessageConverter = Arrays.asList(converters).stream().filter(
                hmc -> hmc instanceof MappingJackson2HttpMessageConverter).findAny().get();

        Assert.assertNotNull("the JSON message converter must not be null",
                this.mappingJackson2HttpMessageConverter);
    }
    
    
    @Before
    public void setup() throws Exception {
        this.mockMvc = webAppContextSetup(webApplicationContext).build();
        
        this.customerRepository.deleteAll();
        
        customer1 = customerRepository.save(new Customer("customer1Id","user1","name1","lastname1"));
        customer2 = customerRepository.save(new Customer("customer2Id","user2","name2","lastname2"));
    }
    
    @Test
	public void customerNotFound() throws Exception{
		 mockMvc.perform(get("/customers/123")
		 			.contentType(contentType))
	                .andExpect(status().isNotFound());
	}
    
    @Test
    public void readSingleCustomer() throws Exception {
        mockMvc.perform(get("/customers/"
                + this.customer1.getId()))
                .andExpect(status().isOk())
                .andExpect(content().contentType(contentType))
                .andExpect(jsonPath("$.id", is(this.customer1.getId())))
                .andExpect(jsonPath("$.username", is(this.customer1.getUsername())))
                .andExpect(jsonPath("$.firstName", is(this.customer1.getFirstName())))
                .andExpect(jsonPath("$.lastName", is(this.customer1.getLastName())));

    }
    
    @Test
    public void readAllCustomers() throws Exception {
        mockMvc.perform(get("/customers"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(contentType))
                .andExpect(jsonPath("$", hasSize(2)))
                .andExpect(jsonPath("$[0].id", is(this.customer1.getId())))
                .andExpect(jsonPath("$[0].username", is(this.customer1.getUsername())))
                .andExpect(jsonPath("$[0].firstName", is(this.customer1.getFirstName())))
                .andExpect(jsonPath("$[0].lastName", is(this.customer1.getLastName())))
                .andExpect(jsonPath("$[1].id", is(this.customer2.getId())))
                .andExpect(jsonPath("$[1].username", is(this.customer2.getUsername())))
                .andExpect(jsonPath("$[1].firstName", is(this.customer2.getFirstName())))
                .andExpect(jsonPath("$[1].lastName", is(this.customer2.getLastName())));
    }
}
